import axios from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';

// 全局配置常量
const BASE_URL = import.meta.env.VITE_APP_API_BASE_URL || ''; // 可从环境变量获取
const TIMEOUT = 30000; // 请求超时时间(毫秒)
let isTokenRefreshing = false;
// 响应状态码枚举
const ResponseCode = {
    SUCCESS: 200, // 成功
    UNAUTHORIZED: 401, // 未授权
    FORBIDDEN: 403, // 禁止访问
    NOT_FOUND: 404, // 资源不存在
    SERVER_ERROR: 500, // 服务器错误
    BAD_GATEWAY: 502, // 网关错误
    SERVICE_UNAVAILABLE: 503, // 服务不可用
    GATEWAY_TIMEOUT: 504 // 网关超时
};

const createAxiosConfig = {
    baseURL: BASE_URL,
    timeout: TIMEOUT,
    withCredentials: true // 跨域携带cookie
};

class Request {
    constructor(config) {
        this.instance = axios.create(config);
        // 修改请求拦截器
        this.instance.interceptors.request.use(
            (config) => this.handleRequest(config),
            (error) => this.handleRequestError(error)
        );

        // 修改响应拦截器
        this.instance.interceptors.response.use(
            (response) => this.handleResponse(response),
            (error) => this.handleResponseError(error)
        );
    }

    /**
     * 请求拦截处理
     * @param {Object} config 请求配置
     */
    handleRequest(config) {
        // 从本地存储获取token和语言国际化设置
        const token = localStorage.getItem('token') || '';
        const language = localStorage.getItem('language') || 'zh-CN';

        // 设置请求头
        config.headers = {
            ...config.headers,
            'Authorization': `Bearer ${token}`,
            'Accept-Language': language,
            'Content-Type': config.headers?.ContentType || 'application/json'
        };

        // 可在请求前添加全局参数
        if (config.method === 'get') {
            config.params = {
                _t: Date.now(), // 防止缓存
                ...config.params
            };
        }

        return config;
    }

    /**
     * 请求错误处理
     * @param {Error} error 错误对象
     */
    handleRequestError(error) {
        console.error('请求拦截出错:', error);
        return Promise.reject(error);
    }

    /**
     * 响应成功处理
     * @param {Object} response 响应对象
     */
    handleResponse(response) {
        const { data, config } = response;

        // 业务状态码处理
        if (data.code !== undefined && data.code !== ResponseCode.SUCCESS) {
            this.handleBusinessError(data, config);
            return Promise.reject(data);
        }

        // 返回简化后的数据
        return data.data !== undefined ? data.data : data;
    }

    /**
     * 处理业务错误
     * @param {Object} data 响应数据
     * @param {Object} config 请求配置
     */
    handleBusinessError(data, config) {
        const errorMsg = data.message || '请求失败';

        // 登录过期处理
        if (data.code === ResponseCode.UNAUTHORIZED) {
            this.handleUnauthorized();
            return;
        }

        // 不显示错误消息的请求（如静默请求）
        if (config.silent) return;

        // 显示错误提示
        ElMessage.error(errorMsg);
    }

    /**
     * 处理未授权情况
     */
    handleUnauthorized() {
        if(isTokenRefreshing) return
        localStorage.removeItem('token');
        ElMessageBox.confirm('登录已过期，请重新登录', '提示', {
            confirmButtonText: '重新登录',
            cancelButtonText: '取消',
            type: 'warning'
        }).then(() => {
            window.location.href = '/login';
        }).finally(()=>{
            isTokenRefreshing = false
        })
    }

    /**
     * 响应错误处理
     * @param {Error} error 错误对象
     */
    handleResponseError(error) {
        // 网络错误处理
        if (!window.navigator.onLine) {
            ElMessage.error('网络连接失败，请检查网络设置');
            return Promise.reject(error);
        }

        // HTTP状态码处理
        if (error.response) {
            this.handleHttpError(error.response.status);
        }

        return Promise.reject(error);
    }

    /**
     * 处理HTTP错误状态码
     * @param {Number} status HTTP状态码
     */
    handleHttpError(status) {
        const errorMap = {
            400: '请求参数错误',
            401: '未授权，请重新登录',
            403: '拒绝访问',
            404: '请求资源不存在',
            500: '服务器内部错误',
            502: '网关错误',
            503: '服务不可用',
            504: '网关超时'
        };

        const errorMessage = errorMap[status] || `连接出错(${status})`;
        ElMessage.error(errorMessage);

        // 特殊状态码处理
        if ([401, 403].includes(status)) {
            this.handleUnauthorized();
        }
    }

    // 封装常用请求方法

    /**
     * GET请求
     * @param {String} url 请求地址
     * @param {Object} params 查询参数
     * @param {Object} config 自定义配置
     */
    get(url, params = {}, config = {}) {
        return this.instance.get(url, { params, ...config });
    }

    /**
     * POST请求
     * @param {String} url 请求地址
     * @param {Object} data 请求体数据
     * @param {Object} config 自定义配置
     */
    post(url, data = {}, config = {}) {
        return this.instance.post(url, data, config);
    }

    /**
     * PUT请求
     * @param {String} url 请求地址
     * @param {Object} data 请求体数据
     * @param {Object} config 自定义配置
     */
    put(url, data = {}, config = {}) {
        return this.instance.put(url, data, config);
    }

    /**
     * DELETE请求
     * @param {String} url 请求地址
     * @param {Object} params 查询参数
     * @param {Object} config 自定义配置
     */
    delete(url, params = {}, config = {}) {
        return this.instance.delete(url, { params, ...config });
    }

    /**
     * 文件上传
     * @param {String} url 请求地址
     * @param {FormData} formData 表单数据
     * @param {Function} onUploadProgress 上传进度回调
     */
    upload(url, formData, onUploadProgress) {
        return this.instance.post(url, formData, {
            headers: { 'Content-Type': 'multipart/form-data' },
            onUploadProgress
        });
    }

    /**
     * 文件下载
     * @param {String} url 请求地址
     * @param {Object} params 查询参数
     */
    download(url, params = {}) {
        return this.instance.get(url, {
            params,
            responseType: 'blob'
        }).then(response => {
            // 处理文件下载逻辑
            const filename = this.getFilenameFromHeaders(response.headers);
            this.saveAs(response.data, filename);
        });
    }

    // 辅助方法

    /**
     * 从响应头获取文件名
     * @param {Object} headers 响应头
     */
    getFilenameFromHeaders(headers) {
        const disposition = headers['content-disposition'];
        if (!disposition) return 'download';

        const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
        const matches = filenameRegex.exec(disposition);
        if (matches && matches[1]) {
            return matches[1].replace(/['"]/g, '');
        }
        return 'download';
    }

    /**
     * 保存文件到本地
     * @param {Blob} blob 文件数据
     * @param {String} filename 文件名
     */
    saveAs(blob, filename) {
        const link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = filename;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }
}

// 创建请求实例并导出
export default new Request(createAxiosConfig);